package com.threeti.mecool.core.application.plan;

import com.threeti.mecool.core.application.Cache;
import com.threeti.mecool.core.application.acl.EmployeeService;
import com.threeti.mecool.core.application.project.ProjectService;
import com.threeti.mecool.core.domain.model.acl.PermissionConst;
import com.threeti.mecool.core.domain.model.acl.PermissionRole;
import com.threeti.mecool.core.domain.model.acl.User;
import com.threeti.mecool.core.domain.model.plan.PlanJobResult;
import com.threeti.mecool.core.domain.model.plan.ProjectCriticalJob;
import com.threeti.mecool.core.domain.model.plan.pojo.Job;
import com.threeti.mecool.core.domain.model.plan.pojo.Plan;
import com.threeti.mecool.core.domain.model.project.Project;
import com.threeti.mecool.core.domain.model.project.ProjectEmployee;
import com.threeti.mecool.core.infrastructure.persistence.acl.UserRepository;
import com.threeti.mecool.core.infrastructure.persistence.plan.PlanJobResultRepository;
import com.threeti.mecool.core.infrastructure.persistence.plan.PlanRepository;
import com.threeti.mecool.core.infrastructure.persistence.plan.ProjectCriticalJobRepository;
import com.threeti.mecool.core.infrastructure.persistence.project.ProjectRepository;
import com.threeti.mecool.core.util.MyAclPermissionEvaluator;
import com.threeti.mecool.framework.util.Lists;
import com.threeti.mecool.framework.util.Sets;
import com.threeti.mecool.framework.util.StringUtil;
import org.apache.commons.lang.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Service
public class PlanService {
    private ProjectCriticalJobRepository projectCriticalJobRepository;
    private UserRepository userRepository;
    private ProjectService projectService;

    @Autowired
    Cache cache;

    @PersistenceContext
    private EntityManager entityManager;

    @Autowired
    private EmployeeService empService;

    @Autowired
    private PlanRepository planRepo;

    @Autowired
    private ProjectRepository projRepo;

    @Autowired
    private PlanJobResultRepository jobResultRepo;

    @Autowired
    private UserRepository userRepo;

    @Autowired
    private PermissionEvaluator permissionEvaluator;

    public void save(ProjectCriticalJob projectCriticalJob) {
        projectCriticalJobRepository.save(projectCriticalJob);
    }

    public List<ProjectCriticalJob> findCriticalJob(String projectCode) {
        return projectCriticalJobRepository.findByProject_Code(projectCode);
    }

    public boolean isCriticalJob(String projectCode, Long jobId) {
        return !projectCriticalJobRepository.findByProject_CodeAndJob_Id(projectCode, jobId).isEmpty();
    }

    public Map<Project, List<Job>> findUserProjectJob(String userLoginName) {
        User user = userRepository.findByloginName(userLoginName);
        List<Project> projectList = projectService.findByUserOwn(user);
        Map<Project, List<Job>> retMap = new HashMap<Project, List<Job>>();
        for (Project project : projectList) {
            retMap.put(project, project.getCategory().getJobs());
        }
        return retMap;
    }

    /**
     * 取得特定用户特定下属的计划
     */
    @Transactional
    public Page<Plan> findSubordinatePlansOfUser(User tryUsingCurrentLoggedInUserWithPermRole, String status, Pageable pageable) {
        PermissionRole permRole = tryUsingCurrentLoggedInUserWithPermRole.getPermissionRole();
        Validate.notNull(permRole, "用户对应的操作权限信息不能为空");
        boolean isAdvancedUser = permRole.isAdvanced();
        List<String> targetUserLoginNames = advancedSubordinateIdentitiesOfUser(tryUsingCurrentLoggedInUserWithPermRole, true);

        if (targetUserLoginNames.size() == 0) {
            return new PageImpl(Lists.newEmptyArrayList());
        }

        //一般用户处理->
        if (!isAdvancedUser) {
            //3.进行第三次交叉筛选(进行项目过滤)
            List<String> targetProjectCodesCurrentUserParticipatedIn = Lists.newArrayList();
            List<Project> projectsCurrentUserParticipatedIn = projectService.findByUserOwn(tryUsingCurrentLoggedInUserWithPermRole);
            for (Project project : projectsCurrentUserParticipatedIn) {
                if (project != null && project.getCode() != null)
                    targetProjectCodesCurrentUserParticipatedIn.add(project.getCode());
            }

            if (targetProjectCodesCurrentUserParticipatedIn.size() == 0) {
                return new PageImpl(Lists.newEmptyArrayList());
            }

            //4.进行最终查询
            if (StringUtil.isEmpty(status)) {
                return planRepo.findByUserLoginNameInAndPlanProjects_ProjectCodeInOrderByPlanDateDesc(targetUserLoginNames, targetProjectCodesCurrentUserParticipatedIn, pageable);
            } else {
                return planRepo.findByUserLoginNameInAndStatusAndPlanProjects_ProjectCodeIn(targetUserLoginNames, status, targetProjectCodesCurrentUserParticipatedIn, pageable);
            }

            //<-
            //拥有高级权限用户的处理->
        } else {
            if (StringUtil.isEmpty(status)) {
                return planRepo.findByUserLoginNameInOrderByPlanDateDesc(targetUserLoginNames, pageable);
            } else {
                return planRepo.findByUserLoginNameInAndStatusOrderByPlanDateDesc(targetUserLoginNames, status, pageable);
            }
        }
        //<-
    }


    public Page<Plan> findSubordinatePlansOfUser(User user, Map<String, String> args, String status, Pageable pageable) {
        PermissionRole permRole = user.getPermissionRole();
        Validate.notNull(permRole, "用户对应的操作权限信息不能为空");
        String planName = args.get("planName");
        String assignedBy = args.get("assignedBy");
        String confirmedBy = args.get("confirmedBy");
        String planType = args.get("planType");
        String planDateString = args.get("planDate");
        String userLoginName = args.get("userLoginName");
        Date planDate;
        try {
            planDate = new SimpleDateFormat("yyyy-MM-dd").parse(planDateString);
        } catch (ParseException ignore) {
            planDate = null;
        }
        boolean isAdvancedUser = permRole.isAdvanced();
        List<String> targetUserLoginNames = advancedSubordinateIdentitiesOfUser(user, true);
        if (targetUserLoginNames.size() == 0) {
            return new PageImpl(Lists.newEmptyArrayList());
        }
        Iterator<String> iterator = targetUserLoginNames.iterator();
        while (iterator.hasNext()) {
            if (user.getLoginName().equals(iterator.next())) {
                iterator.remove();
            }
        }
        StringBuilder targetUserLoginNamesString = new StringBuilder();
        for (String targetUserLoginName : targetUserLoginNames) {
            targetUserLoginNamesString.append("'").append(targetUserLoginName).append("',");
        }
        targetUserLoginNamesString.deleteCharAt(targetUserLoginNamesString.length() - 1);
        List<Object> sqlParams = new ArrayList<Object>();
        StringBuilder from = new StringBuilder("\n from dm_plan p join dm_plan_project pp on pp.plan=p.id");
        StringBuilder groupBy = new StringBuilder("\n group by p.id, p.version, p.user_login_name, p.name, p.plan_date, p.status, p.deny_notes, p.change_notes, p.assigned_by, p.type, p.confirmed_by");
        StringBuilder where = new StringBuilder();
        where.append("\n where p.user_login_name in (").append(targetUserLoginNamesString).append(')');
        if (!StringUtil.isEmpty(status)) {
            where.append("\n and p.status=?");
            sqlParams.add(status);
        }
        if (!StringUtil.isEmpty(planName)) {
            where.append("\n and p.name like ?");
            sqlParams.add("%" + planName + "%");
        }
        if (!StringUtil.isEmpty(assignedBy)) {
            where.append("\n and p.assignedBy=?");
            sqlParams.add(assignedBy);
        }
        if (!StringUtil.isEmpty(confirmedBy)) {
            where.append("\n and p.confirmedBy=?");
            sqlParams.add(confirmedBy);
        }
        if (!StringUtil.isEmpty(planType)) {
            if ("2".equals(planType)) {
                where.append("\n and p.type='").append(Plan.TYPE_ASSIGNMENT).append("'");
            } else if ("1".equals(planType)) {
                where.append("\n and p.type is null");
            }
        }
        if (!StringUtil.isEmpty(userLoginName)) {
            where.append("\n and p.user_login_name=?");
            sqlParams.add(userLoginName);
        }
        if (planDate != null) {
            where.append("\n and p.plan_date=?");
            sqlParams.add(planDate);
        }
        if (!isAdvancedUser) {
            //3.进行第三次交叉筛选(进行项目过滤)
            List<String> targetProjectCodesCurrentUserParticipatedIn = Lists.newArrayList();
            List<Project> projectsCurrentUserParticipatedIn = projectService.findByUserOwn(user);
            for (Project project : projectsCurrentUserParticipatedIn) {
                if (project != null && project.getCode() != null)
                    targetProjectCodesCurrentUserParticipatedIn.add(project.getCode());
            }
            if (targetProjectCodesCurrentUserParticipatedIn.size() == 0) {
                return new PageImpl(Lists.newEmptyArrayList());
            }
            StringBuilder targetProjectCodesString = new StringBuilder();
            for (String projectCode : targetProjectCodesCurrentUserParticipatedIn) {
                targetProjectCodesString.append("'").append(projectCode).append("',");
            }
            targetProjectCodesString.deleteCharAt(targetProjectCodesString.length() - 1);
            where.append("\n and pp.project_code in (").append(targetProjectCodesString).append(")");
        }
        StringBuilder countSql = new StringBuilder();
        countSql.append("select count(*) from(select count(0)").append(from).append(where).append(groupBy).append(")");
        Query query = entityManager.createNativeQuery(countSql.toString());
        for (int i = 0; i < sqlParams.size(); i++) {
            query.setParameter(i + 1, sqlParams.get(i));
        }
        long count = ((Number) query.getSingleResult()).longValue();
        StringBuilder sql = new StringBuilder();
        sql.append("select id, version, user_login_name, name, plan_date, status, deny_notes, change_notes, assigned_by, type, confirmed_by")
                .append(" from (select rownum ROWNUM_, row_.* from(select p.*").append(from).append(where).append(groupBy).append("\n order by p.plan_date desc")
                .append(") row_ where rownum<=?) where ROWNUM_>?");
        sqlParams.add(pageable.getOffset() + pageable.getPageSize());
        sqlParams.add(pageable.getOffset());
        query = entityManager.createNativeQuery(sql.toString());
        for (int i = 0; i < sqlParams.size(); i++) {
            query.setParameter(i + 1, sqlParams.get(i));
        }
        List<Object[]> dataList = query.getResultList();
        List<Plan> plans = new ArrayList<Plan>(dataList.size());
        for (Object[] data : dataList) {
            Plan plan = new Plan();
            plans.add(plan);
            plan.setId(((Number) data[0]).longValue());
            plan.setVersion(((Number) data[1]).intValue());
            plan.setUserLoginName((String) data[2]);
            plan.setName((String) data[3]);
            plan.setPlanDate((Date) data[4]);
            plan.setStatus((String) data[5]);
            plan.setDenyNotes((String) data[6]);
            plan.setChangeNotes((String) data[7]);
            plan.setAssignedBy((String) data[8]);
            plan.setType((String) data[9]);
            plan.setConfirmedBy((String) data[10]);
        }
        return new PageImpl<Plan>(plans, pageable, count);
    }

    /**
     * 取得特定用户特定下属的任务
     */
    public Page<PlanJobResult> findSubordinateTasksOfUser(User tryUsingCurrentLoggedInUserWithPermRole, String status, Pageable pageable) {
        PermissionRole permRole = tryUsingCurrentLoggedInUserWithPermRole.getPermissionRole();
        Validate.notNull(permRole, "用户对应的操作权限信息不能为空");
        boolean isAdvancedUser = permRole.isAdvanced();
        List<String> targetEmpIds = advancedSubordinateIdentitiesOfUser(tryUsingCurrentLoggedInUserWithPermRole, false);
        if (targetEmpIds.size() == 0) {
            return new PageImpl(Lists.newEmptyArrayList());
        }

        //一般用户处理->
        if (!isAdvancedUser) {
            //3.进行第三次交叉筛选(进行项目过滤)
            List<String> targetProjectCodesCurrentUserParticipatedIn = Lists.newArrayList();
            List<Project> projectsCurrentUserParticipatedIn = projectService.findByUserOwn(tryUsingCurrentLoggedInUserWithPermRole);
            for (Project project : projectsCurrentUserParticipatedIn) {
                if (project != null && project.getCode() != null)
                    targetProjectCodesCurrentUserParticipatedIn.add(project.getCode());
            }

            if (targetProjectCodesCurrentUserParticipatedIn.size() == 0) {//TODO jay:需要额外排除高级只读用户
                return new PageImpl(Lists.newEmptyArrayList());
            }

            //4.进行最终查询
            if (StringUtil.isEmpty(status)) {
                return jobResultRepo.findByEmpIdInAndProjectCodeIn(targetEmpIds, targetProjectCodesCurrentUserParticipatedIn, pageable);
            } else {
                return jobResultRepo.findByEmpIdInAndJobStatusAndProjectCodeIn(targetEmpIds, status, targetProjectCodesCurrentUserParticipatedIn, pageable);
            }

            //<-
            //拥有高级权限用户的处理->
        } else {
            if (StringUtil.isEmpty(status)) {
                return jobResultRepo.findByEmpIdIn(targetEmpIds, pageable);
            } else {
                return jobResultRepo.findByEmpIdInAndJobStatus(targetEmpIds, status, pageable);
            }
        }
    }

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Autowired
    public void setProjectService(ProjectService projectService) {
        this.projectService = projectService;
    }

    @Autowired
    public void setProjectCriticalJobRepository(ProjectCriticalJobRepository projectCriticalJobRepository) {
        this.projectCriticalJobRepository = projectCriticalJobRepository;
    }

    //返回不重复的雇员Id集合
    private List<String> getDistinctSubordinateEmpIds(List<ProjectEmployee> subEmps) {
        Set<String> targetEmpIdSet = Sets.newHashSet();
        for (ProjectEmployee subEmp : subEmps) {
            if (subEmp.getEmpId() != null)
                targetEmpIdSet.add(String.valueOf(subEmp.getEmpId()));
        }
        if (targetEmpIdSet.size() == 0) return Lists.newEmptyArrayList();

        return Lists.newArrayList(targetEmpIdSet);
    }

    /* 返回不重复的雇员userloginname集合 */
    private List<String> getDistinctSubordinateEmpUserLoginNames(List<ProjectEmployee> subEmps) {
        Set<String> targetUserLoginNameSet = Sets.newHashSet();
        for (ProjectEmployee subEmp : subEmps) {
            if (subEmp.getEmpId() != null) {
                User user = userRepo.findByEmployeeEmpId(subEmp.getEmpId());
                if (user != null) {
                    targetUserLoginNameSet.add(user.getLoginName());
                }
            }
        }
        if (targetUserLoginNameSet.size() == 0) return Lists.newEmptyArrayList();
        return Lists.newArrayList(targetUserLoginNameSet);
    }

    @SuppressWarnings("unchecked")
    public List<String> advancedSubordinateIdentitiesOfUser(User tryUsingCurrentLoggedInUserWithPermRole, boolean isReturnUserLoginNames) {
        String cacheKey = "advancedSubordinateIdentitiesOfUser" +
                ":" + tryUsingCurrentLoggedInUserWithPermRole.getLoginName() +
                ":" + isReturnUserLoginNames;
        List<String> cachedResult = (List<String>) cache.get(cacheKey);
        if (cachedResult != null) return cachedResult;

        PermissionRole permRole = tryUsingCurrentLoggedInUserWithPermRole.getPermissionRole();
        boolean isAdvancedUser = permRole.isAdvanced();
        List<String> rtnList;
        //拥有高级权限用户的处理 (此类用户最大的特点是可以凌驾于各个项目之外查看各个项目相关的数据,并且一般来说只拥有只读的权限，如老板，高级经理等，但受制于该用户所能管辖或查看的组织机构，并且无法查看项目经理制定的计划)->
        if (isAdvancedUser) {
            if (CollectionUtils.isEmpty(permRole.getManagedOrgCodeEntries())) {
                return Lists.newEmptyArrayList();
            }
            //根据所能管辖或查看的组织机构找到对应的所有项目经理下相关下属的数据
            List<Long> managerEmpIds = projRepo.findByOrgCodeIn(permRole.getManagedOrgCodeEntries());
            List<ProjectEmployee> allTheSubEmps = Lists.newArrayList();
            for (Long managerEmpId : managerEmpIds) {
                List<ProjectEmployee> subEmpsOfSpecifiedManager = empService.findSubordinateEmployeesByEmpId(managerEmpId);
                allTheSubEmps.addAll(subEmpsOfSpecifiedManager);
            }

            if (isReturnUserLoginNames)
                rtnList = getDistinctSubordinateEmpUserLoginNames(allTheSubEmps);
            else
                rtnList = getDistinctSubordinateEmpIds(allTheSubEmps);

            //<-
            //一般用户处理->
        } else {
            Validate.notNull(tryUsingCurrentLoggedInUserWithPermRole.getEmployee(), "用户对应的雇员信息不能为空");
            Long currentUserEmpId = tryUsingCurrentLoggedInUserWithPermRole.getEmployee().getEmpId();
            String currentUserLoginName = tryUsingCurrentLoggedInUserWithPermRole.getLoginName();
            String currentPermRoleId = tryUsingCurrentLoggedInUserWithPermRole.getPermissionRole().getId().toString();
            String currentUserEmpIdString = currentUserEmpId.toString();

            rtnList = new LinkedList<String>();
            StringBuilder sql = new StringBuilder(200);
            //<editor-fold desc="String projectIdString">
            sql.append("\n select distinct pe.project");
            sql.append("\n from dm_project_employee pe");
            sql.append("\n where pe.emp_id='").append(currentUserEmpId).append("'");
            List<Number> projectIdList = entityManager.createNativeQuery(sql.toString()).getResultList();
            StringBuilder projectIdStringBuilder = new StringBuilder(projectIdList.size() * 11 + 10);
            Iterator<Number> numberIterator = projectIdList.iterator();
            projectIdStringBuilder.append(-9999);
            while (numberIterator.hasNext()) {
                projectIdStringBuilder.append(',').append(numberIterator.next());
            }
            String projectIdString = projectIdStringBuilder.toString();
            //</editor-fold>
            sql = new StringBuilder(500);
            sql.append("\n select pe.id, pe.parent parent, u.login_name, pe.emp_id, u.permission_role, pe.project");
            sql.append("\n from dm_project_employee pe");
            sql.append("\n join dm_user u on u.emp_pk=pe.emp_id");
            sql.append("\n where pe.project in (").append(projectIdString).append(')');
            List<Object[]> list = entityManager.createNativeQuery(sql.toString()).getResultList();
            List<ProjectUser> currentUserRelated = new ArrayList<ProjectUser>(list.size());
            Map<String, ProjectUser> projectUserMap = new HashMap<String, ProjectUser>();
            for (Object[] v : list) {
                String projEmpId = String.valueOf(v[0]);
                String parentId = String.valueOf(v[1]);
                String loginName = String.valueOf(v[2]);
                String empId = String.valueOf(v[3]);
                String permRoleId = String.valueOf(v[4]);
                String projectId = String.valueOf(v[5]);
                ProjectUser projectUser = new ProjectUser(projEmpId, loginName, empId, permRoleId, projectId, parentId);
                projectUserMap.put(projectId + ":" + projEmpId, projectUser);
                if (currentUserEmpIdString.equals(empId)) {
                    String cachePermEntryKeyChecking = "PERM_ENTRY:" + permRoleId + ":";
                    String cachePermEntryKey = cachePermEntryKeyChecking + PermissionConst.MODULE_SUB_PLANTASK_AUDIT[0];
                    boolean hasPlanAuditPerm = cache.has(cachePermEntryKey, cachePermEntryKeyChecking, permEntryGenerator, permRoleId);
                    if (hasPlanAuditPerm) {
                        currentUserRelated.add(projectUser);
                    }
                }
            }
            for (ProjectUser projectUser : projectUserMap.values()) {
                if (projectUser.parentProjEmpId != null) {
                    ProjectUser parent = projectUserMap.get(projectUser.projectId + ":" + projectUser.parentProjEmpId);
                    projectUser.setParent(parent);
                }
            }
            Set<String> sets = new HashSet<String>();
            for (ProjectUser projectUser : currentUserRelated) {
                if (isReturnUserLoginNames) projectUser.fillLoginName(sets);
                else projectUser.fillEmpId(sets);
            }
            rtnList.addAll(sets);



            //1.取得所有下属,待进一步筛选
//            List<ProjectEmployee> subEmpsFirstRound = empService.findSubordinateEmployeesOfUser(tryUsingCurrentLoggedInUserWithPermRole);
//            List<ProjectEmployee> subEmpsSecondRound = Lists.newArrayList();
//            //2.进行第二次交叉筛选(由于权限关系，需要再次对下属用户进行过滤)
//            for (ProjectEmployee subEmp : subEmpsFirstRound) {
//                ProjectEmployee targetParent = recursivelyGetParentWithPlanAuditPermissionOf(subEmp);
//                while (targetParent != null) {
//                    if (targetParent.getEmpId().equals(currentUserEmpId)) {
//                        subEmpsSecondRound.add(subEmp);
//                        break;
//                    } else {
//                        targetParent = recursivelyGetParentWithPlanAuditPermissionOf(targetParent);
//                    }
//                }
//            }
//            if (isReturnUserLoginNames)
//                rtnList = getDistinctSubordinateEmpUserLoginNames(subEmpsSecondRound);
//            else
//                rtnList = getDistinctSubordinateEmpIds(subEmpsSecondRound);
        }
        //<-
        cache.set(cacheKey, rtnList);
        return rtnList;
    }

    private Cache.Generator permEntryGenerator = new Cache.Generator() {
        @SuppressWarnings("unchecked")
        @Override
        public Map<String, Object> get(String...key) {
            String permRoleId = key[0];
            String sql = "select permission_entry from dm_permissionrole_perm_entry where permission_role=" + permRoleId;
            List<String> list = entityManager.createNativeQuery(sql).getResultList();
            Map<String, Object> map = new HashMap<String, Object>();
            for (String value : list) {
                String entryKey = value.substring(0, value.indexOf(';'));
                map.put(String.format("PERM_ENTRY:%s:%s", permRoleId, entryKey), null);
            }
            return map;
        }
    };

    private static class ProjectUser {
        String projectId;
        String projEmpId;
        String loginName;
        String empId;
        String permRoleId;
        Set<ProjectUser> children = new HashSet<ProjectUser>();
        ProjectUser parent;
        String parentProjEmpId;

        private ProjectUser(String projEmpId, String loginName, String empId, String permRoleId, String projectId, String parentProjEmpId) {
            this.projEmpId = projEmpId;
            this.loginName = loginName;
            this.empId = empId;
            this.permRoleId = permRoleId;
            this.projectId = projectId;
            this.parentProjEmpId = parentProjEmpId;
        }

        void setParent(ProjectUser parent) {
            if (parent != null) {
                this.parent = parent;
                parent.children.add(this);
            }
        }

        void fillLoginName(Collection<String> collection) {
            collection.add(loginName);
            for (ProjectUser child : children) {
                child.fillLoginName(collection);
            }
        }

        void fillEmpId(Collection<String> collection) {
            collection.add(empId);
            for (ProjectUser child : children) {
                child.fillEmpId(collection);
            }
        }
    }

    private ProjectEmployee recursivelyGetParentWithPlanAuditPermissionOf(ProjectEmployee subEmp) {
        ProjectEmployee parent = subEmp.getParent();

        MyAclPermissionEvaluator permEvaluator = (MyAclPermissionEvaluator) permissionEvaluator;
        if (parent == null || parent.getEmpId() == null) return null;
        User parentUser = userRepo.findByEmployeeEmpId(parent.getEmpId());
        if (parentUser == null || parentUser.getLoginName() == null) return null;

        boolean hasTargetParentUserPlanAuditPerm =
                permEvaluator.hasPermission(parentUser.getLoginName(), PermissionConst.MODULE_SUB_PLANTASK_AUDIT[0], PermissionConst.MODULE_SUB_PLANTASK_AUDIT[1],
                        PermissionConst.P_ADMIN_STR);
        if (hasTargetParentUserPlanAuditPerm) {
            return parent;
        } else {
            return recursivelyGetParentWithPlanAuditPermissionOf(parent);
        }
    }
}
